////////////////////////////////////////////////
// DESCRIPTION:
//    Extended Serial port support
//
// Legal Notices:
//   Copyright (c) 2008, Telliam Consulting, LLC.
//   All rights reserved.
//
//   Redistribution and use in source and binary forms, with or without modification,
//   are permitted provided that the following conditions are met:
//
//   * Redistributions of source code must retain the above copyright notice, this list
//     of conditions and the following disclaimer.
//   * Redistributions in binary form must reproduce the above copyright notice, this
//     list of conditions and the following disclaimer in the documentation and/or other
//     materials provided with the distribution.
//   * Neither the name of Telliam Consulting nor the names of its contributors may be
//     used to endorse or promote products derived from this software without specific
//     prior written permission.
//
//   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY
//   EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
//   OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT
//   SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
//   INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
//   TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR 
//   BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
//   CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 
//   ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH
//   DAMAGE. 
//
using System;
using System.Text;
using Microsoft.SPOT.Hardware;

namespace FusionWare.SPOT.Hardware
{
    /// <summary>Extends Microsoft.SPOT.Serial to provide some useful missing functionality</summary>
    /// <remarks>
    /// Since the Microsoft SerialPort class is sealed this is not a derived class, rather
    /// it aggregates the SerialPort class and provides a cast operator to allow casting to
    /// the serial port type to get acces to the unerlying pot. The key extensions are:
    /// <list type="bullet">
    /// <item><description >Simplified construction of both configuration and port objects in a single constructor</description></item>
    /// <item><description >Writing of string data using <see cref="System.Text.Encoding">Text Encoding</see></description></item>
    /// </list>
    /// </remarks>
    public class ComPort : IDisposable
    {
        SerialPort Port;

        /// <summary>Release resources controlled by the port</summary>
        public void Dispose()
        {
            Port.Dispose();
            Port = null;
        }

        /// <summary>Create a new port with the specified configuration</summary>
        /// <param name="Cfg">Configuration for the port</param>
        /// <remarks>
        /// This creates a new port instance with the specified configuration 
        /// and a defult UTF8 Text Encoding.
        /// </remarks>
        public ComPort(SerialPort.Configuration Cfg)
        {
            Port = new SerialPort(Cfg);
            this._Encoding = new System.Text.UTF8Encoding();
        }

        /// <summary>Create a new port with the specified configuration</summary>
        /// <param name="com">Com port ID</param>
        /// <param name="speed">BaudRate for the port</param>
        /// <param name="flowControl">true for XON/XOFF flow control; false for none</param>
        /// <remarks>
        /// This creates a new port instance with the specified configuration 
        /// and a defult UTF8 Text Encoding.
        /// </remarks>
        public ComPort(SerialPort.Serial com, SerialPort.BaudRate speed, bool flowControl)
            : this(new SerialPort.Configuration(com, speed, flowControl))
        {
        }

        /// <summary>Writes binary data out the serial port</summary>
        /// <param name="Buffer">Data to send</param>
        /// <param name="Offset">Starting index in Buffer of the first byte to send</param>
        /// <param name="Count">Total number of bytes to send</param>
        /// <remarks>
        /// This is a simple wrapper around the standard port function 
        /// <see cref="M:Microsoft.SPOT.Hardware.SerialPort.Write">SerialPort.Write</see>
        /// </remarks>
        public int Write(byte[] Buffer, int Offset, int Count)
        {
            return Port.Write(Buffer, Offset, Count);
        }

        /// <summary>Writes binary data out the serial port</summary>
        /// <param name="Buffer">Data to send</param>
        /// <remarks>
        /// This is a simple wrapper around the standard port function 
        /// <see cref="M:Microsoft.SPOT.Hardware.SerialPort.Write">SerialPort.Write</see>
        /// that writes the entire byte array out
        /// </remarks>
        public int Write(byte[] Buffer)
        {
            return Port.Write(Buffer, 0, Buffer.Length);
        }

        /// <summary>Writes a string to the serial port using the current text encoding</summary>
        /// <param name="Txt">String to send to the port</param>
        public int Write(string Txt)
        {
            return Write(this._Encoding.GetBytes(Txt));
        }

        /// <summary>Reads data from a serial port</summary>
        /// <param name="buffer">buffer to read data into</param>
        /// <param name="offset">buffer indext to start reading data into</param>
        /// <param name="count">count of bytes to read</param>
        /// <param name="timeout">timeout for the read operation in milliseconds</param>
        /// <returns>Number of bytes actually read.</returns>
        /// <remarks>
        /// This method reads data from the serial port. If the return value is
        /// less than count a timeout occured. 
        /// </remarks>
        public int Read(byte[] buffer, int offset, int count, int timeout)
        {
            return Port.Read(buffer, offset, count, timeout);
        }

        /// <summary>Flushes the port</summary>
        public void Flush()
        {
            Port.Flush();
        }

        /// <summary>Sets/Gets the port configuration</summary>
        /// <value>Port Configuration</value>
        public SerialPort.Configuration Configuration
        {
            get { return this.Port.Config; }
            set { this.Port.Config = value; }
        }

        /// <summary>Get/Set the text encoding for the port</summary>
        /// <value>The text encoding for the port</value>
        /// <remarks>
        /// Default encoding is UTF8. You can override that by creating 
        /// a new text encoding instance and setting this property.
        /// Changes to the encoding take place immediately.
        /// </remarks>
        public System.Text.Encoding Encoding
        {
            get { return _Encoding; }
            set { _Encoding = value; }
        }
        private System.Text.Encoding _Encoding;

        /// <summary>Cast operator to allow treating this type as if it was derived from <see cref="Microsoft.SPOT.Hardware.SerialPort" /></summary>
        /// <param name="p">Port to convert</param>
        /// <returns>The internally wrapped port</returns>
        /// <remarks>
        /// Since the framework <see cref="Microsoft.SPOT.Hardware.SerialPort">SerialPort</see> class is marked sealed
        /// this allows applications to treat the FusionWare.Hardware.SerialPort as if it was derived from the standard one
        /// </remarks>
        public static implicit operator SerialPort(ComPort p)
        {
            return p.Port;
        }
    }
}
